/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sysno2signature;

import cz.mzk.oai.metadataRepository.metadata.MetadataFormat;
import cz.mzk.oai.metadataRepository.repository.collections.Item;
import cz.mzk.oai.metadataRepository.repository.AlephBase;
import cz.mzk.oai.metadataRepository.repository.collections.MetadataCollection;
import cz.mzk.oai.metadataRepository.repository.NoSuchRecordException;
import cz.mzk.oai.metadataRepository.repository.Repository;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dom4j.Document;

/**
 *
 * @author Martin Rehanek, Martin.Rehanek@gmail.com
 */
public class Converter {

    private Map<String, String> sysnoSignatureMap;
    private static final String separator = ":";
    private static final int NORMALIZED_SYSNO_LENGTH = 9;
    private String alephBase;
    private int incorrectRecords = 0;
    private int totalRecords = 0;

    /**
     * Constructor that processes file with mappings of sysno to signature.
     * Every row of the file is read, parsed and put as new item into internal Map
     * @param transformationTable file with mapping
     * @throws FileNotFoundException 
     * @throws IOException
     */
    public Converter(File transformationTable, String alephBase) throws FileNotFoundException, IOException {
        this.alephBase = alephBase;
        sysnoSignatureMap = new HashMap<String, String>();
        BufferedReader reader = new BufferedReader(new FileReader(transformationTable));
        while (reader.ready()) {
            String line = reader.readLine();
            totalRecords++;
            String[] result = line.split(Converter.separator);
            if (result.length != 2) {
                //System.err.println("Incorrect number of tokens in the line '" + line + "'" );
                incorrectRecords++;
                continue;
            } else {
                String sysno = result[0];
                String signature = result[1];
                //System.out.println("sysno: " + sysno);
                //System.out.println("signature: " + signature);
                if (sysnoSignatureMap.containsKey(sysno)) {
                    System.err.println("sysno " + sysno + " already present");
                    continue;
                } else {
                    sysnoSignatureMap.put(sysno, signature);
                }
            }
        }
//        System.out.println("wrong records: " + incorrectRecords);
//        System.out.println("total records: " + totalRecords);
    }

    /**
     * Converts sysno into signature
     * @param sysno system number
     * @return signature or null if not found
     */
    public String convertSysno(String sysno) {
        try {
            String normalizedSysno = normalize(sysno);
            return sysnoSignatureMap.get(normalizedSysno);
        } catch (IllegalArgumentException e) {

            return null;
        }
    }

    /**
     * Converts sysno '1064990' into '001064990' i.e. adds extra 0s so that resulting String
     * has length NORMALIZED_SYSNO_LENGTH
     * @param sysno
     * @return
     */
    private String normalize(String sysno) {
        if (sysno == null) {
            throw new NullPointerException("sysno");
        }
        if (sysno.length() == NORMALIZED_SYSNO_LENGTH) {
            return sysno;
        } else if (sysno.length() < NORMALIZED_SYSNO_LENGTH) {
            StringBuilder result = new StringBuilder(NORMALIZED_SYSNO_LENGTH);
            for (int i = 0; i < (NORMALIZED_SYSNO_LENGTH - sysno.length()); i++) {
                result.append('0');
            }
            result.append(sysno);
            return result.toString();
        } else {//sysno.length() < NORMALIZED_SYSNO_LENGTH
            throw new IllegalArgumentException("sysno to long: '" + sysno + "'");
        }
    }

    /**
     * Creates transformation table with rows of this format: "sysno:signature".
     * This table is than used for mapping.
     * @param repository repository who's items are included in map being created
     * @param transformationTable file to store the mapping into
     */
    public static void createTransformationTable(Repository repository, String alephBase, File transformationTable) {
        try {
            FileWriter out = null;
            /*  if (!transformationTable.canWrite()) {
            System.err.println("cannot write to file '" + transformationTable.getAbsolutePath() + "'");
            return;
            }*/
            out = new FileWriter(transformationTable);
            //int counter = 0;
            for (MetadataCollection col : repository.getCollectionsByAlehBase(alephBase)) {
                //MetadataCollection col = repository.getCollection("mollMapsBefore1800");
                System.out.println("processing collection " + col.getName());
                List<Item> items = col.getItems(MetadataFormat.marc21);
                for (Item item : items) {
                    String itemId = item.getId();
                    String sysno = idToSysno(itemId, alephBase);
                    try {
                        Document doc = col.getRecord(itemId, MetadataFormat.marc21, false);
                        //String signature = doc.valueOf("/marc21:record/marc21:datafield[@tag=910]/marc21:subfield[code='b']/text()");
                        String signature = doc.valueOf("/marc21:record/marc21:datafield[@tag=910]/marc21:subfield[@code='b']/text()");
//                    System.out.println("id: " + itemId);
//                    System.out.println("sysno: " + sysno);
//                    System.out.println("signature: " + signature);
                        out.write(sysno + Converter.separator + signature + '\n');
                    } catch (NoSuchRecordException ex) {
                        ex.printStackTrace();
                    }
                }
            }
            out.close();
        } catch (IOException ex) {
            Logger.getLogger(Converter.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Transforms id into sysno by cutting all not necessary prefixes
     * @param id for example "oai:aleph.mzk.cz:MZK03-001042910"
     * @return sysno, for example 001042910
     */
    public static String idToSysno(String id, String alephBase) {
        String prefix = "oai:aleph.mzk.cz:" + alephBase + '-';
        String sysno = id.substring(prefix.length(), id.length());
        return sysno;
    }
}
